//
//  ViewController.m
//  JKThreadTest
//
//  Created by 王冲 on 2018/10/22.
//  Copyright © 2018年 JK科技有限公司. All rights reserved.
//

#import "ViewController.h"
#import "ThreadLockViewController.h"
#import "Pthread_rwlockViewController.h"
#import "Dispatch_barrier_asyncViewController.h"
@interface ViewController ()

/**
  票的数量
 */
@property(nonatomic,assign) int ticketCount;

/**
 钱的数量
 */
@property(nonatomic,assign) int moneyCount;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor whiteColor];
    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]initWithTitle:@"addLock" style:UIBarButtonItemStylePlain target:self action:@selector(addLock)];
    
    self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]initWithTitle:@"rw" style:UIBarButtonItemStylePlain target:self action:@selector(rwLock)];
    
    // 看是否会线程堵塞
    // 面的题 1
    // [self interview1];
    // 面的题 2
    // [self interview2];
    // 面的题 3
    // [self interview3];
    // 面的题 4
    // [self interview4];
    // 面的题 5
    // [self interview5];
    // 面的题 6
    // [self interview6];
}

#pragma mark 加锁的控制器代码
-(void)addLock{
    
    ThreadLockViewController *threadLockViewController = [ThreadLockViewController new];
    [self.navigationController pushViewController:threadLockViewController animated:YES];
}

#pragma mark 读写的加锁
-(void)rwLock{
    
    /** Pthread_rwlock
     
    Pthread_rwlockViewController *pthread_rwlockViewController = [Pthread_rwlockViewController new];
    [self.navigationController pushViewController:pthread_rwlockViewController animated:YES];
    */
    
    // dispatch_barrier_async
    Dispatch_barrier_asyncViewController *dispatch_barrier_asyncViewController = [Dispatch_barrier_asyncViewController new];
    [self.navigationController pushViewController:dispatch_barrier_asyncViewController animated:YES];
}


- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
    // 取票的安全隐患展示
    // [self ticketTest];
    // 取钱存钱的测试(多线程安全的隐患)
    [self moneyTest];
}

#pragma mark 9.取钱存钱的测试(多线程安全的隐患)
-(void)moneyTest{
    
    self.moneyCount = 100;
    
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_async(queue, ^{
        
        for (int i = 0; i<10; i++) {
            
            // 存钱
            [self saveMoney];
        }
    });
    
    dispatch_async(queue, ^{
        
        for (int i = 0; i<10; i++) {
            
            // 取钱
            [self drawMoney];
        }
    });
}

// 存钱
-(void)saveMoney{
    
    int oldMoney = self.moneyCount;
    sleep(0.2);
    oldMoney = oldMoney + 50;
    self.moneyCount = oldMoney;
    
    NSLog(@"存进去50元，余额是%d - %@",oldMoney,[NSThread currentThread]);
}

// 取钱
-(void)drawMoney{
    
    int oldMoney = self.moneyCount;
    sleep(0.2);
    oldMoney = oldMoney - 20;
    self.moneyCount = oldMoney;
    
    NSLog(@"花去20元，余额是%d - %@",oldMoney,[NSThread currentThread]);
}

#pragma mark 8.买票的测试(多线程安全的隐患)
-(void)ticketTest{
    
    self.ticketCount = 20;
    
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_async(queue, ^{
        
        for (int i = 0; i<10; i++) {
            
            [self buyTicket];
        }
    });
    
    dispatch_async(queue, ^{
        
        for (int i = 0; i<10; i++) {
            
            [self buyTicket];
        }
    });
}

-(void)buyTicket{
    
    int oldTickCount = self.ticketCount;
    sleep(0.2);
    oldTickCount --;
    self.ticketCount = oldTickCount;
    
    NSLog(@"还有%d张票-%@",oldTickCount,[NSThread currentThread]);
}

#pragma mark 7.多线程 GCD 队列组：notify(唤醒):  可以在touchesBegan里面调用
-(void)notify{
    
    // 创建队列组
    dispatch_group_t group = dispatch_group_create();
    // 创建并发队列
    dispatch_queue_t queue = dispatch_queue_create("my_queue", DISPATCH_QUEUE_CONCURRENT);
    
    // 添加异步任务
    dispatch_group_async(group, queue, ^{
        
        for (int i = 0; i<5; i++) {
            
            NSLog(@"任务1-%@",[NSThread currentThread]);
        }
    });
    
    dispatch_group_async(group, queue, ^{
        
        for (int i = 0; i<5; i++) {
            
            NSLog(@"任务2-%@",[NSThread currentThread]);
        }
    });
    
    // 等前面的任务执行完毕后，会自动执行这个任务
    //    dispatch_group_notify(group, queue, ^{
    //        dispatch_async(dispatch_get_main_queue(), ^{
    //            for (int i = 0; i < 5; i++) {
    //                NSLog(@"任务3-%@", [NSThread currentThread]);
    //            }
    //        });
    //    });
    
    //    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    //        for (int i = 0; i < 5; i++) {
    //            NSLog(@"任务3-%@", [NSThread currentThread]);
    //        }
    //    });
    
    dispatch_group_notify(group, queue, ^{
        
            NSLog(@"最后执行任务3");
    });
 
}

#pragma mark 6.看下面面试题的打印结果
/**
  打印结果是：1、3
  原因
  performSelector:withObject:afterDelay:的本质是往Runloop中添加定时器
  子线程默认没有启动Runloop
  可以添加下面的代码来启动runLoop
  [[NSRunLoop currentRunLoop]addPort:[[NSPort alloc]init] forMode:NSDefaultRunLoopMode];
  [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
 */
-(void)interview6{
    
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_async(queue, ^{
        
        NSLog(@"1111");
        
        //[self performSelector:@selector(test) withObject:nil afterDelay:.0];
        
        [self performSelector:@selector(test) withObject:nil];
        
        NSLog(@"3333");
        
        
        
    });
    
}

-(void)test{
    
     NSLog(@"2222");
}

#pragma mark 5.看下面的代码是否会产生死锁：不会(并行队列不会产生死锁：不用谁等谁等情况)
-(void)interview5{
    
    NSLog(@"---------1-------");
    
    // 并行队列
    dispatch_queue_t queue2 = dispatch_queue_create("myqueue2", DISPATCH_QUEUE_CONCURRENT);
    // dispatch_async: 不要求在当前线程立马执行任务
    dispatch_async(queue2, ^{
        
        NSLog(@"---------2-------");
        
        dispatch_sync(queue2, ^{
            
            NSLog(@"---------3-------");
        });
        
        NSLog(@"---------4-------");
    });
    
    NSLog(@"---------5-------");
    
    
}

#pragma mark 4.看下面的代码是否会产生死锁：不会(不同的队列不会产生死锁)
-(void)interview4{
    
    NSLog(@"---------1-------");
    
    // 串行队列
    dispatch_queue_t queue = dispatch_queue_create("myqueue", DISPATCH_QUEUE_SERIAL);
    // 并行队列
    dispatch_queue_t queue2 = dispatch_queue_create("myqueue2", DISPATCH_QUEUE_CONCURRENT);
    // dispatch_async: 不要求在当前线程立马执行任务
    dispatch_async(queue, ^{
        
        NSLog(@"---------2-------");
        
        dispatch_sync(queue2, ^{
            
            NSLog(@"---------3-------");
        });
        
        NSLog(@"---------4-------");
    });
    
    NSLog(@"---------5-------");
    
    
}

#pragma mark 3.看下面的代码是否会产生死锁：会
-(void)interview3{
    
    NSLog(@"---------1-------");
    
    // 串行队列
    dispatch_queue_t queue = dispatch_queue_create("myqueue", DISPATCH_QUEUE_SERIAL);
    // dispatch_async: 不要求在当前线程立马执行任务
    dispatch_async(queue, ^{
        
        NSLog(@"---------2-------");
        
        dispatch_sync(queue, ^{
            
            NSLog(@"---------3-------");
        });
        
        NSLog(@"---------4-------");
    });
    
    NSLog(@"---------5-------");
    
    
}

#pragma mark 2.看下面的代码是否会产生死锁：不会
-(void)interview2{
    
    NSLog(@"---------1-------");
    
    dispatch_queue_t queue = dispatch_get_main_queue();
    // dispatch_async: 不要求在当前线程立马执行任务
    dispatch_async(queue, ^{
        
        NSLog(@"---------2-------");
    });
    
    NSLog(@"---------3-------");
    
    
}

#pragma mark 1.看下面的代码是否会产生死锁：会
-(void)interview1{
    
     NSLog(@"---------1-------");
    
    dispatch_queue_t queue = dispatch_get_main_queue();
    // dispatch_sync:立马在当前线程同步执行任务
    dispatch_sync(queue, ^{
        
        NSLog(@"---------2-------");
    });
    
    NSLog(@"---------3-------");
    
}


@end
